from application import settings
from ..paradag import SequentialProcessor
from process.algorithms import OPERATIONS
import cv2
import numpy as np
import urllib.request
from urllib.parse import quote
import os
import asyncio
import time
import urllib
import shutil
from datasource.views.op_list import OpViewSet


def message(sender, msg_type, msg):
    text = {
        'sender': sender,
        'contentType': msg_type,
        'content': msg,
    }
    return text


def mkdir(path):
    folder = os.path.exists(path)
    if not folder:
        os.makedirs(path)


def pathIsFolder(path):
    if os.path.isdir(path):
        return True
    return False


import traceback

def executeSrc(param):
    global localimg
    folder = 'media/temp'
    img_src_type = param[0].params['img_src_type']
    image_url = None  # 默认没有图像地址

    try:
        if img_src_type == "视频源":
            return param[0].node_id, param[0].params["img"], True, image_url
        elif img_src_type == "图片源":
            img_path = param[0].params['img']
            img_path = quote(img_path, safe=':/')
            with urllib.request.urlopen(img_path) as url_response:
                s = url_response.read()
            arr = np.asarray(bytearray(s), dtype=np.uint8)
            img = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED)
            upload_img = param[0].params['img'].split('/')[-1].split('.')[0]
            upload_img = urllib.parse.unquote(upload_img)

            # 保存图像到本地目录
            mkdir(f"media/temp")

            src_img = f'media/temp/{upload_img}_origin.png'
            cv2.imwrite(src_img, img)

            # 将本地文件路径转换为 URL
            image_url = os.path.join("/" + src_img)
            print(f"Image URL generated: {image_url}")
            localimg = img
            print(f"Image source type '图片源': localimg set to {src_img}")
            return param[0].node_id, src_img, True, image_url
        elif img_src_type == "上传":
            upload_img = param[0].params['img']
            img = cv2.imread(upload_img)
            upload_img = param[0].params['img'].split('/')[-1].split('.')[0]
            # 确保文件夹存在
            mkdir(f"media/temp")
            src_img = f'media/temp/{upload_img}_origin.png'
            cv2.imwrite(src_img, img)
            localimg = img
            print(f"Image source type '上传': localimg set to {src_img}")
            # 将本地文件路径转换为 URL
            image_url = os.path.join("/"+src_img)
            print(f"Image URL generated: {image_url}")
            return param[0].node_id, src_img, True, image_url
        else:
            print(f"Unknown image source type: {img_src_type}")
            return None, None, False
    except Exception as e:
        print(f"An error occurred: {e}")
        traceback.print_exc()
        return None, None, False


def executeFork(param):
    print(f'判断节点测试: {param[1]}')
    image_url = None  # 假设没有图像路径
    if param[0].params['condition'] is True:
        return param[0].node_id, param[1], True, image_url
    return param[0].node_id, param[1], False, image_url



def executeParams(param):
    return param[0].node_id, param[1], param[2]


def executeBasicOpr(param):
    if isinstance(param[1], list):
        save_path_list = []
        info_list = []
        image_url_list = []  # 新增用于存储图像的 URL
        for img_path in param[1]:
            img, info = OPERATIONS[param[0].params['operation']](img, param[0].params)
            save_path = f'{img_path.split(".")[0]}_{param[0].opr}_{str(time.time())}.png'
            cv2.imwrite(save_path, img)
            save_path_list.append(save_path)
            info_list.append(info)

            # 生成图片的 URL
            image_url = os.path.join("/"+save_path)
            image_url_list.append(image_url)

            print("info:", info_list)

        return param[0].node_id, save_path_list, info_list, image_url_list
    else:
        img = cv2.imread(param[1])
        img, info = OPERATIONS[param[0].opr](img, **param[0].params)

        # 创建目标文件夹
        mkdir(f"media/temp/{param[0].opr}")

        save_path = f"media/temp/{param[0].opr}/{param[1].split('.')[0].split('/')[-1]}_{param[0].opr}_{str(time.time())}.png"
        cv2.imwrite(save_path, img)

        # 生成图片的 URL
        image_url = os.path.join("/" +save_path)
        print("info:", info)

        return param[0].node_id, save_path, info, image_url


localimg = None

import os
import cv2
import numpy as np
import urllib
import traceback


def executeCustomOp(param):
    global localimg
    folder = 'media/temp'
    input_img_path = param[1]
    print("===========TEST==============",input_img_path)
    localimg = cv2.imread(input_img_path)
    try:
        op_view = OpViewSet()
        result = op_view.get_querycode(param[0].params['opName'])

        if hasattr(result, 'content'):
            print(f"Result content: {getattr(result, 'content', 'No content attribute')}")
            code = result.content
        else:
            raise ValueError("Result does not have a 'content' attribute.")

        context = {
            'img': locals().get('localimg', None),
        }
        exec(code, globals(), context)

        img = context.get('img')
        if img is not None:
            # 使用节点ID和时间戳构造唯一文件名
            unique_filename = f"{param[0].node_id}_origin.png"
            save_path = os.path.join(folder, unique_filename)

            # 确保保存目录存在
            os.makedirs(folder, exist_ok=True)

            # 保存图像
            cv2.imwrite(save_path, img)
            localimg = img
            print(f"Image saved at: {save_path}")
            image_url = os.path.join("/" + unique_filename)
            return param[0].node_id, save_path, True, image_url
        else:
            raise ValueError("Image processing failed: No image found in context.")
    except Exception as e:
        print(f"An error occurred: {e}")
        traceback.print_exc()
        return param[0].node_id, None, False, None


class CVExecuter:
    def __init__(self, notifier=None):
        self.notifier = notifier
        self.__level = {}

    def param(self, vertex):
        """
        return:
        param[0]: vertex
        param[1]: img path(if has)
        param[2]: other infos in json format
        """
        if isinstance(self.__level.get(vertex), tuple):
            return vertex, self.__level.get(vertex)[0], self.__level.get(vertex)[1]
        else:
            return vertex, self.__level.get(vertex)

    def execute(self, param):
        print(f'Executing: {param[0].opr} by {param[0].params}')

        image_urls = []  # 用于存储返回的图像 URL

        if param[0].opr == 'img_src':
            node_id, save_path_list, info_list, image_urls = executeSrc(param)
            return node_id, save_path_list, info_list, image_urls
        elif param[0].opr == 'customOp': # 自定义算子
            return executeCustomOp(param)

        elif param[0].opr == 'fork':
            node_id, save_path_list, info_list, image_urls = executeFork(param)
            return node_id, save_path_list, info_list, image_urls

        elif param[0].opr == 'params':
            return executeParams(param)

        else:
            assert param[1] is not None
            # 如果上一个节点是 fork 类型，则根据条件执行
            if isinstance(param[2], bool):
                if param[2] == bool(param[0].should_execute):
                    node_id, save_path, info, image_urls = executeBasicOpr(param)
                    return node_id, save_path, info, image_urls
                else:
                    return param[0].node_id, param[1], False, image_urls
            else:
                node_id, save_path, info, image_urls = executeBasicOpr(param)
                return node_id, save_path, info, image_urls

    def deliver(self, vertex, result):
        self.__level[vertex] = (result[1], result[2])

    def report_start(self, vertices):
        print('Start to run:', vertices[0].opr)
        return vertices[0].opr

    def report_running(self, vertices):
        print('Currently running: ', vertices)
        return vertices

    async def report_finish(self, vertices_result):
        """ 仅返回任务的完成状态 """
        results = {}  # ✅ 存储任务完成状态

        for vertex, result in vertices_result:
            print(f'Finished running {vertex}')

            if self.notifier:
                loop = asyncio.get_event_loop()
                task = loop.create_task(self.notifier.send_json(message('system', 'INFO', f'{vertex.opr}执行完毕')))
                await task
                task = loop.create_task(self.notifier.send_json(message('system', 'RES',
                                                                        {'node_id': result[0], 'status': 'success',
                                                                         'img': result[1], 'info': result[2]})))
                await task

            # ✅ 只存储任务是否完成，不存储执行结果
            results[vertex] = "completed"

        return results  # ✅ 只返回任务完成状态


def executeOpr(dag, processor=SequentialProcessor(), executer=CVExecuter()):
    pass
    # dag_run(dag, processor=processor, executer=executer)
